{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch  \n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei']\n",
    "plt.rcParams['axes.unicode_minus'] = False\n",
    "\n",
    "from torchvision import datasets\n",
    "import torchvision.transforms as transforms\n",
    "from torch.utils.data.sampler import SubsetRandomSampler\n",
    "\n",
    "num_workers = 0\n",
    "\n",
    "batch_size = 20\n",
    "valid_size = 0.2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "transform = transforms.ToTensor()\n",
    "\n",
    "train_data = datasets.MNIST(root='data', train=True, download=True, transform=transform)\n",
    "\n",
    "test_data = datasets.MNIST(root='data', train=False, download=True, transform=transform)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_train = len(train_data)\n",
    "indices = list(range(num_train))\n",
    "np.random.shuffle(indices)\n",
    "split = int(np.floor(valid_size*num_train))\n",
    "train_idx, valid_idx = indices[split:], indices[:split]\n",
    "train_sampler, valid_sampler = SubsetRandomSampler(train_idx), SubsetRandomSampler(valid_idx)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, \n",
    "                                           sampler=train_sampler, num_workers=num_workers)\n",
    "valid_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size,\n",
    "                                           sampler=valid_sampler, num_workers=num_workers)\n",
    "test_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size,\n",
    "                                           num_workers=num_workers)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Net(\n",
      "  (fc1): Linear(in_features=784, out_features=512, bias=True)\n",
      "  (fc2): Linear(in_features=512, out_features=512, bias=True)\n",
      "  (fc3): Linear(in_features=512, out_features=10, bias=True)\n",
      "  (dropout): Dropout(p=0.2, inplace=False)\n",
      ")\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<All keys matched successfully>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "class Net(nn.Module):\n",
    "  def __init__(self):\n",
    "    super(Net, self).__init__()\n",
    "    hidden1 = 512\n",
    "    hidden2 = 512\n",
    "    self.fc1 = nn.Linear(28 * 28, hidden1)\n",
    "    self.fc2 = nn.Linear(hidden1, hidden2)\n",
    "    self.fc3 = nn.Linear(hidden2, 10)\n",
    "    self.dropout = nn.Dropout(0.2)\n",
    "\n",
    "  def forward(self, x):\n",
    "    x = x.view(-1, 28*28)\n",
    "    x = F.relu(self.fc1(x))\n",
    "    x = self.dropout(x)\n",
    "    \n",
    "    x = F.relu(self.fc2(x))\n",
    "    x = self.dropout(x)\n",
    "\n",
    "    x = self.fc3(x)\n",
    "    return(x)\n",
    "\n",
    "model = Net()\n",
    "print(model)\n",
    "model.load_state_dict(torch.load('model.pt'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class_correct = list(0. for i in range(10))\n",
    "class_total = list(0. for i in range(10))\n",
    "model.eval()\n",
    "for data, target in test_loader:\n",
    "  output = model(data)\n",
    "\n",
    "  _, pred = torch.max(output, 1)\n",
    "\n",
    "  correct = np.squeeze(pred.eq(target.data.view_as(pred)))\n",
    "  for i in range(batch_size):\n",
    "    label = target.data[i]\n",
    "    class_correct[label] += correct[i].item()\n",
    "    class_total[label] += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataiter = iter(train_loader)\n",
    "data, target = dataiter.next()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[969.0, 1127.0, 1013.0, 998.0, 963.0, 869.0, 939.0, 1002.0, 951.0, 981.0]\n",
      "[980.0, 1135.0, 1032.0, 1010.0, 982.0, 892.0, 958.0, 1028.0, 974.0, 1009.0]\n"
     ]
    }
   ],
   "source": [
    "output = model(data)\n",
    "correct = np.squeeze(pred.eq(target.data.view_as(pred)))\n",
    "print(class_correct)\n",
    "print(class_total)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "correct rate of Number 0 on test set is 98.877551% (969/980)\n",
      "correct rate of Number 1 on test set is 99.295154% (1127/1135)\n",
      "correct rate of Number 2 on test set is 98.158915% (1013/1032)\n",
      "correct rate of Number 3 on test set is 98.811881% (998/1010)\n",
      "correct rate of Number 4 on test set is 98.065173% (963/982)\n",
      "correct rate of Number 5 on test set is 97.421525% (869/892)\n",
      "correct rate of Number 6 on test set is 98.016701% (939/958)\n",
      "correct rate of Number 7 on test set is 97.470817% (1002/1028)\n",
      "correct rate of Number 8 on test set is 97.638604% (951/974)\n",
      "correct rate of Number 9 on test set is 97.224975% (981/1009)\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "  print('correct rate of Number {} on test set is {:5f}% ({:.0f}/{:.0f})'.\n",
    "        format(i, class_correct[i]*100/class_total[i], class_correct[i], class_total[i]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "findfont: Font family ['sans-serif'] not found. Falling back to DejaVu Sans.\n"
     ]
    },
    {
     "data": {
      "image/png": "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6W+//eaMly5dauImTZo4uV122cXEH3/8sZOrWrVqmcwHm87u6SVJI0aMMPGsWbOc3K233lqQOa130kknFfT9UL723XdfZ9yqVavIbf1z4tdeey0vc0LpNWzY0Bl37tw5ctvzzz/fxPb3mkKx++C++eabkdv5PXHt51ug8K655hoT16tXL6fX8Hv1H3vssc74lltuMbHfP7cQPSaRG7tHrd2fVpL2339/E5988smRr/Hhhx86Y3ud5/vvv3dyjRs3dsb2c4nK6vkTKD/2WuBll13m5OxjSO3atSNf48cff3TG7733njP+73//a2L/+7n9DJEDDzzQydnHvg4dOji5yZMnm3jo0KGRcysrXIkLAAAAAAAAADHGIi4AAAAAAAAAxFi5t1N46623Mo5tY8eOjczVrVvXxM2bN3dy9mXRBxxwQNZzW7lypTOeOXOmif1WD/bl1f7tkKgYTjjhBGfcr18/E2+22WZO7tdff3XG119/vYmXL1+eh9mhotl5552dcevWrZ2xfTxZtmxZIaaEMnbEEUc44913393E/i1d2d7i5d+C49+atnjxYhO3b9/eyd14442Rr3vppZeaeMiQIVnNBfnRp08fZ2zfiujfXmq3z8gX+/zFr2luTSxumW679/nHIsTHXXfd5YzPPPNME9vfgSTpueeeK8icorRp08bE2267rZN77LHHTDx8+PBCTQlp+O2azj333Mhtv/zySxP/8ssvTu6oo46K3G/rrbd2xnbLhqeeesrJ/fzzz9GTRUH534mffvppE9vtEyS3JVSm9ik+v4WCzW9biYrtwQcfdMZ2241tttkmcj9/zfCrr74y8Q033ODk/DU926GHHuqM7e9LjzzyiJOz1xj9Y93gwYNN/Pzzzzu5fLQu4kpcAAAAAAAAAIgxFnEBAAAAAAAAIMZYxAUAAAAAAACAGCv3nrhlZdGiRSZ+5513IrfL1HN3Y+zeYXYPXsntw/HMM8/k/B4oP37PUr/nj83/Ox4/fnxe5oSKy+8t6ctHfxzkn93r+N///reTy9S7yTZ79mxnbPdOSiaTTi5Tj23/dS666CITN2jQwMkNHDjQxFtssYWTu//++028evXqyPdD7rp06WLiDh06OLlvv/3WxJ9++mnB5rSe3UvZ74E7btw4E//++++FmhIK5PDDD8+YX7VqlYkz9dxG+QrD0Bnb/45/+uknJ2f/neZLjRo1TOz3JuzRo4eJ/Xmfd955+Z0YsuY/X6ZWrVomfu+995ycfb7rn1+cccYZJvZroWnTps54u+22M/GLL77o5I477jgTL1y4MOPcUfZq1qxpYvs5MJL7TJkFCxY4uTvvvNPEPDOm8vKPC9dee62JL7jgAicXBIGJ/e/K9jM97rjjDieX6/Nl6tev74yrVq1q4r59+zo5+/lcft/wQuNKXAAAAAAAAACIMRZxAQAAAAAAACDGiqadQj40bNjQGT/wwAMmrlLFXf/u16+fibnNo+J44YUXTHz00UdHbvfEE0844z59+uRtTigO++67b8a8fXs7Ko5q1f73sZlt+wTJbbnStWtXJ+fffpYtv53CbbfdZuJBgwY5uS233NLEfu2NGTPGxLNmzcppLsjs1FNPNbH9dyG55xaFYLcEkaTu3bubeO3atU5uwIABJqbVRnE49NBD08bp2LcnfvHFF3mbE/Ln+OOPd8ZvvPGGif0WKfatqqXht49q27atiQ8++ODI/UaOHJnT+yH/Nt98c2dst764++67I/dbuXKlM3700UdNbH8OStKuu+4a+Tr+rfeFaAOCaJ06dTJx7969ndycOXNM3KZNGye3ePHi/E4MFYL9mSBJvXr1MrHdPkGSfvzxRxPbrUwl6eOPP87p/e0WCZK00047mdhf43n11VdN7LdPtfnzfvLJJ01ciPZjXIkLAAAAAAAAADHGIi4AAAAAAAAAxBiLuAAAAAAAAAAQY/TEzeCyyy5zxg0aNDDxokWLnNyMGTMKMidsmkaNGjljux+c3//J7lNp9wWUpKVLl+Zhdqjo7N5v5557rpP7/PPPnfF//vOfgswJ5ePTTz91xuedd56Jc+2BuzF2b1u7z6kkHXDAAXl5T6S39dZbO+NMfSFz7UOZq4suusgZ272dp02b5uTeeeedgswJhVOaY0GhaxO5uffee51xu3btTLz99ts7ucMPP9zEfk+/E088Maf391/H7p/q++6770x8ww035PR+yL8zzjgjMuf3WbafL5JJ69ats37/Dz/80Bnzvat8Zeqfbn+/mTt3biGmgwrG70nrP3/BtmbNGhMfdNBBTq5Lly4m3mOPPSJfY8WKFc54zz33jBz738m23XbbyNe1/fLLL8640M+Q4EpcAAAAAAAAAIgxFnEBAAAAAAAAIMZop+D561//auLevXtHbtepUydn/PXXX+dtTig7zz//vDOuX79+5LbDhw838axZs/I2JxSPo446ysT16tVzcmPHjnXGK1euLMickD9VqkT/HtS/BagQ7Fta/bllmmvfvn1NfNZZZ5X5vCojvz3PDjvsYOIRI0YUejqOpk2bRuY4lyl+mW5p/v33350x7RQqhs8++8wZ77fffiZu3ry5kzv22GNN3KtXLyc3f/58Ez/++ONZv/+TTz7pjCdPnhy57cSJE03MuXV8+Z9TdqsNvyWLfVvzvvvu6+ROPvlkE9etW9fJ+ccbO3/hhRc6ObvGpk6dmnHuKHv2bew++5iSSCSc3IsvvmjiL774ouwnhgrh7bffdsZ2qy77u7MkNW7c2MT/+te/nFymVj12iwa/fUMmmdonrFu3zhmPHj3axH//+9+d3Lx587J+z7LAlbgAAAAAAAAAEGMs4gIAAAAAAABAjLGICwAAAAAAAAAxRk9cT4cOHUxcvXp1J/fWW2+Z+IMPPijYnLBp7D5OLVu2jNxu3Lhxztjv6wNszP77729iv2/PyJEjCz0d5MEll1xiYr9XUnnr2LGjiVu0aOHk7Ln687Z74qJs/PHHH87Y7gVn96uU3P7ZCxcuzMt8GjZsaOJMve0mTJiQl/dH+TnssMOccbdu3SK3Xbx4sTOeO3duXuaE/Fq0aJGJ7d6D/vi6664rk/fbddddnbHdn93vg3nNNdeUyXsiv958801nbB8b/L63do/aTD0r/de87LLLnPHLL79s4r/85S9Ozu4/aZ+HoTAaNGhgYv8c0n4GwM033+zk+vTpY+KhQ4c6uQ8//NDEdh9USfr2229NPGXKlIxz23vvvU3sr8/wGRYPK1ascMZ2r+w6deo4OfuZVPazqiTpt99+M/GcOXOcnF2H9vdxSTrwwANLOeOUYcOGOeMbbrjBxH5P70LjSlwAAAAAAAAAiDEWcQEAAAAAAAAgxljEBQAAAAAAAIAYq/Q9cWvUqOGMjz32WBOvWrXKydk9UlevXp3fiSFn9evXd8Z2/xK/z7HN79u1dOnSsp0Yis52223njNu0aWPiGTNmOLnRo0cXZE7IL7vvbHmw+5LttddeTs4+1mUyf/58Z8znWdnz+3/NmjXLxJ07d3Zyr7zyiokHDRqU0/vts88+ztjvUbnzzjubOFPPwrj1ecam88+JqlSJvn7jP//5T76ngyLk98G0jzF+313/8wfx5PdnP+2000zsP+Nh6623jnyd++67z8R+LaxcudIZjxo1ysR2X0xJOuaYY0zctGlTJ2d/viI/7rzzThNfddVVWe9nf9706NHDyfnjsuAfX+zn3XTt2rXM3w+bzu8t6//bz8UTTzzhjDP1xPWfYWHX92OPPebk1q5du8lzKytciQsAAAAAAAAAMcYiLgAAAAAAAADEWKVvp9CrVy9n3KJFCxOPHTvWyU2cOLEgc8Kmufrqq53xAQccELntCy+8YGK7XQaQjb/97W/OuGHDhiZ+7bXXCjwbVAY33nijiS+77LKs9/v+++9NfM455zi5OXPmbPK8kJn9+RIEgZM7/vjjTTxixIicXn/BggXO2G+ZsM0222T1Ov6tY6j4unTpEpnzb2N88MEH8z0dFIFTTz3VGZ999tnO2L499bfffivInJBfb775pon9Y0q3bt1M7B9T7FYbfvsEX//+/U285557OrkTTzwx7WtKG57ToOzZt7g/88wzTu7pp582cbVq7tLSTjvtZOJMrXzKit1yTHJrtU+fPk5uwIABeZ8PCufaa681cWlaZ1xyySXOONfz8ELjSlwAAAAAAAAAiDEWcQEAAAAAAAAgxljEBQAAAAAAAIAYq3Q9ce3ec5J00003OeMlS5aYuF+/fgWZE8rWVVddlfW2l19+uYmXLl2aj+mgiDVp0iQyt2jRogLOBMXq1Vdfdca77757Tq8zdepUE0+YMGGT5oTSmz59uolPO+00J9e8eXMT77bbbjm9/siRIzPmH3/8cRN37949crsVK1bk9P6Ilx133NHEdr9K39y5c53xp59+mrc5oXgcd9xxGfMvv/yyiSdNmpTv6aDA7P646ca5sj9//L6rdk/cdu3aObl69eqZeOHChWUyF7jWrl1rYv9zolmzZpH7HXnkkSauXr26k+vbt6+JMz2/ZlPYzyBo1apVXt4D5eOCCy5wxnbPY783s2/KlCkmHjVqVNlOrEC4EhcAAAAAAAAAYoxFXAAAAAAAAACIsUrRTqF+/fom/te//uXkqlat6oztW1c//PDD/E4M5c6+BWf16tU5v87ixYsjX8e+fWTrrbeOfI06deo442zbQti3uEjSddddZ+Lly5dn9RrIzQknnBCZe+mllwo4ExSKfWtWlSrRvwfNdLvpsGHDnPH2228fua3/HuvWrdvYFNPq2LFjTvsh/7744ou0cVn67rvvstpun332ccZff/11PqaDPDv00ENNnOk49cILLxRiOigy/ufbsmXLnPFdd91VyOmgCD377LPO2G6ncPrppzs5uzUerRDj5a233orM2a2k/HYKa9asMfGjjz7q5B566CFn/I9//MPEmdoHoeI78MADTex/ztSsWTNyP79l5iWXXGLiP//8s4xmV1hciQsAAAAAAAAAMcYiLgAAAAAAAADEGIu4AAAAAAAAABBjRdkT1+9zO3bsWBPvsssuTm7WrFnO+KabbsrfxBA7X375ZZm8znPPPWfiefPmObltt93WxCs5g/cAACAASURBVH4fp3z4+eefTXzLLbfk/f0qm8MOO8zE2223XTnOBOVhyJAhJh44cGDkdi+//LIzztTLtjR9brPddujQoVm/Joqf3cvZjn30wC0O9rMgfAsWLDDxvffeW4jpoAjYPQTt81pJ+vXXX53xpEmTCjInFC//XMc+3zrppJOcXCKRMPG///1vJzdz5sw8zA5l4Y033jCx/321WrX/LVFdeOGFTm633XZzxm3bts3q/ebOnVvKGSJu7Od71KpVK3I7v0+73VNbkt5///2ynVg54EpcAAAAAAAAAIgxFnEBAAAAAAAAIMaKsp1C06ZNnXGrVq0it73qqqucsd9eARXPq6++6oz9227y4dRTT81pvzVr1pg4023SY8aMccaffvpp5LbvvfdeTnNBdk4++WQT+61bPv/8cxO/++67BZsTCmfUqFEm7tWrl5Nr0KBB3t9//vz5Jp42bZqTu+iii0zst3VB5RaGYdoYxemYY46JzM2ZM8fEixcvLsR0UATsdgr+MeSVV16J3M+/5bVu3bomtmsRyOSLL74w8c033+zk7rjjDhPfeuutTu6ss84y8YoVK/I0O+TCPod99tlnndxpp50WuV+7du0ic2vXrnXG9rGpd+/epZ0iypn/+XHttddmtd9TTz3ljMeNG1dWU4oNrsQFAAAAAAAAgBhjERcAAAAAAAAAYoxFXAAAAAAAAACIsaLpidukSRMTv/HGG5Hb+T0MX3755bzNCeXjlFNOccZ2/5Tq1atn/Tp77723iU8//fSs93vkkUec8ffffx+57fPPP2/i6dOnZ/0eKJwtt9zSGXfo0CFy25EjR5rY78uE4jB79mwTd+3a1cl16tTJxD179szL+99yyy0mHjx4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99xzJu7Zs2fWrzl58mQTjx492snVq1fPxP75dNOmTZ2x3S7Mb5uIiqdZs2YmvvPOO53cFVdcYWK/dUs+fPXVV3l/j1xxJS4AAAAAAAAAxBiLuAAAAAAAAAAQYyziAgAAAAAAAECMxbon7uabbx6Ze/zxx53x4MGD8z0dxw033OCM7f5Au+yyi5M75ZRTTExP3Pzr06dPeU/BcfDBB5vY7xtms3sDSdLMmTPzNidkr2XLls547NixkdvOmzfPxJdffrmTW758eeR+fs+yZcuWmfi+++5zcqtWrUr7fig8uweuJN12220m9vsQ2v38/D5OJ554oomnTZvm5PyecTfffLOJ/R5iY8aMiXz/L7/80sT77befUPElk0kTJxKJjNvaPf3tGBXH/PnznfGwYcNMPGDAACdn//unJ27l5vdOt/vg/vTTT05u9913N7F9rrExP/zwgzO2e93++eefTq5Dhw4mfvrppyNfs2bNms7YflYAsvfwww87Y7tn6G677ebkMh0rtthiCxOfdNJJWb//nnvuaeIGDRo4uSpV3GvJDjnkkLSxb+XKlc74jjvuMPHGPguRG/vfrX9e6n/+ZGvChAkm9mvKPp8+7LDDnFy3bt0iX/Pcc891xmvWrMlpbig/9rrJCSec4OTs9b+y6onrHwdtP/74Y5m8Rz5wJS4AAAAAAAAAxBiLuAAAAAAAAAAQY7Fup9C/f//I3EcffVTAmWzc66+/buJLLrnEydmXhSP/jj/++Micf1tRWRkyZEjk+9etW9fENWrUiHyNJUuWOOO7777bxJn+LaDs2bfJ27eo+9566y1nfP3115t40qRJWb/f9ttv74xffPFFE9epU8fJ2beN+e+PwvJbbdj/9v3bBO1bUx944AEnN2XKlKzf074V8uOPP3Zyjz32mImvvvpqJ7fvvvua2L4NW5IuuuiirN8f8cFto5WbfYwJgsDJ2bcw+7lM/HYumdoAIb66du1q4quuusrJLVy40MR2nUila6GQyaxZs0y81157Obknnngicj/73Me/ZR65sc8ZpLL5HmR/P9mYffbZx8T/93//l3Fb+zb5Vq1aRW5nt3aQpJ49e5p40KBBTm7x4sVZzROZvfnmmyZu3769k7NbwOVq4sSJzvjaa681sd+K0v5eLbl189JLLzm5Z599dpPnhsLy68uWj/YG/neg33//3cSl+S5faFyJCwAAAAAAAAAxxiIuAAAAAAAAAMQYi7gAAAAAAAAAEGOx64m76667mtjvE2n3tfnqq68KNqdsvP322yb2e+Ii/7bccksTV6vmlrXdP8XuGbkx9uv4vS9Hjx7tjLfbbjsT+70w58+fb2K7p5D/uo0bN3Zydo8Wv4fY7NmzM84dm+amm24y8TbbbOPk7N5Mfq+5b7/9Nqf3s3uGSVKLFi0itx07dmxO74Gyd9xxxznjMAxNvG7dOic3btw4E9911115mU/v3r0j52bXWOvWrfPy/gDyp0GDBs74ggsuMLF97JGkxx9/3MR+T1x7Wz/nn9s89dRTkTnE13777Wdi/5zU7sG+dOnSvM9l7ty5WW/7xx9/mNivaVRMX3/9ddo4Hfv5IjvssIOTs89vzj//fCdXu3ZtE/vPA7j55puznywi2f3SM/Us9dmfU3bvWkl68MEHs3qNESNGOOMePXpEbvuXv/wl67khHmrVquWMjzzySBP7PY39Z4GUherVqztj+/vbmjVryvz9ygpX4gIAAAAAAABAjLGICwAAAAAAAAAxFrt2CmeeeaaJ7dYKkvT888+beOLEiQWbE+LPvl1j2223dXLDhg3L6jX89h12O4M+ffpk3Penn34y8ZNPPunkHnjgARNnuq1szJgxzrhDhw4mbtSokZOjnULZeuihh5zxqaeeauJly5Y5OfuWrlzbJ0ju7RvXX3+9k7NvcR0/fryT88corPr165v4wAMPzHo//7iQb/773X777QV9fwCbzm6h4B/77RZMkyZNcnL2ra8TJkyIfP0LL7zQGbdq1coZn3LKKSb2b2+3j3/2+0nS8uXLI98T+de0adPIXKE/C4455hhnXKNGjcht/VtnUbmsXLnSxLNmzXJydt367RTsNhylaZuH7H366aeRObt9yxZbbOHk7r//fhP7t60fccQRZTS7/7HXAyRpxowZJv7Pf/7j5Ow2nSg/e+21lzO2W6l89NFHTs5vVZerOnXqmHjPPfd0cn6dxBVX4gIAAAAAAABAjLGICwAAAAAAAAAxxiIuAAAAAAAAAMRY7Hridu3a1cR+r5J777230NNBBdGiRYvI3DfffJPVa/h9by+++GIT+73g3n77bWd85ZVXmnjKlClZvZ8v23mi7LVu3doZ23/fS5cudXJTp07N6T38XlD9+/c3cZs2bSLfv1+/fjm9H/LD7hm58847R2733nvvOeNXXnklX1Mqtbp16zpju+f2vHnzCj0dABF23333tLEkjRo1ysR2H/fS8J8ZsM022zhj+zkVnTp1cnIff/yxif3PRXs+06dPz2luyN6WW27pjE8++eTIbe1nOOTLZpttZuJbb701MuefX3399df5nRgqrJNOOikyV6tWLRN36dLFyQ0cODBvc6pMXnjhBRP7fUnt78T+c2nsPsf+96B8sHvFS9IzzzxjYr9Xu/3smxdffNHJ0de9cA477LDIXL6eA3P66aeb2H7WiSS9++67eXnPssaVuAAAAAAAAAAQYyziAgAAAAAAAECMxa6dgs2/BWvChAnlNBPE3fbbb5/Tfs2aNTOxfWm976GHHnLGPXv2dMarVq3K6f0zmTRpUtoYFYN/q32PHj2c8VVXXRW5r31L+xdffFGm88KmsdspZJJIJJzxokWL8jGdYVcuHAAAD8FJREFUnOy0007OeJ999jEx7RSKU9++fct7CsiBfd5btWrVvL/fggULnPE999yTNpbcW1EvvPBCJ2ffjnjcccc5uc8++2yT54nMClErNv826fbt25t41113jdzvkUceccazZ88u24mhwvLrJtNn2JIlS0zsf19D2bD/Px4+fHjkdn6LlO7du5v4tNNOc3L16tUzcYcOHTZ1ihvlt52x/zv8Vi7dunUzca5tEhFt8803N7H//XjhwoUmttu9SdL/+3//z8R+646tttrKxIcffnjG9w+CIDK3xRZbZNw3LrgSFwAAAAAAAABijEVcAAAAAAAAAIgxFnEBAAAAAAAAIMbKvSeu3b9C2rCvEpCNWrVqmThTnxPfFVdcYeI6deo4uaefftrEl1566SbMLjv2f4MkrV692sT56LmL/5k6daoz3nfffU1cv359J/f5559n9ZrbbLONM/b7NodhGLnvW2+9ZeLff/89q/dDYdg9tTIda8aPH1+I6WStSpX//c523bp15TgTAMVg2LBhJh41apSTs49/r7zyipOzz6dGjx6dp9lVLmvWrHHG33//vYn9/vxHH320iSdPnpzT+/l9Cs866yxnfNttt2X1Oo899lhO74/i17FjR2fsrxfY7D64cXr+ANzjv/9ZYPfu9r8D2/zep/73p19//TVy32QyaeLzzjvPydnn8/azISRp0KBBJr7uuuucHM8q2XR239lddtklcruXXnrJGdvfX6ZNm+bk7M+91157LeP7H3nkkWnnIkm33nqriX/77Tcn98QTT2R83ULiSlwAAAAAAAAAiDEWcQEAAAAAAAAgxljEBQAAAAAAAIAYK/eeuKeddpozbtq0qYkXLFhQ6Onk7MQTT4zM+b2qUPbs/jiZeo367L5e/n5+z698sPuknn/++U7O7zGH/Lngggucce3atU3coUMHJ2f3yy0N/xhx9tlnm7hz585ObujQoTm9B/LvgAMOMHFpjjXlze4jVZHmDSD+/PN1u+/tXXfd5eQefPBBEzdp0sTJ3XPPPXmYXfHzn5twxBFHmNjv+X/77beb2O6PK0nPP/+8iffaay8nZ/esbNOmjZPze1YuWbLExFtvvbWTmzNnjol/+OEHAevttttuJh4wYEDkdsuWLXPGDz/8cN7mhE1jPx+kWbNmTm7ixIkmzvT8j015NkjPnj1N/Mwzzzi5IUOGmNjviXvUUUeZ2O/xfdxxx+U8H6T8+eefJv7mm2+cXMOGDU1s96eVpMcff9zEmXohb4z9ObTjjjs6OfuZRBdffLGToycuAAAAAAAAACArLOICAAAAAAAAQIyVezuFiqpVq1bO+IQTTojc9oYbbsj3dJAj+zL5v/71r07OHl9//fVObtiwYc74t99+y+n97ZYJy5cvd3L+LYjInxUrVjjjjh07mrht27ZOrnXr1pGvM2XKFBO/9tprTm7w4MHOuEuXLiaeOXOmk5s1a1bmCQObYOnSpc441+MXAKTz7rvvmti/9XT8+PEmvvPOO50c7RTKxty5c0185plnOrkbb7zRxO3bt3dy9ti+pVSS/vvf/5p43LhxTm7EiBHO+OWXXzax377nrbfeMvHChQvTzh+Vg32rveQeD7baaqvI/W6++WZnPH369LKdGHJmf3+S3GO63UJQkrp27WriF198Mb8Tk9u+QZIOO+wwE0+aNMnJ7brrriY+5JBDnNyxxx5r4rFjx5blFCuNlStXmthuUydJ1ar9b3myrD4jdthhB2dct25dE0+ePNnJnXPOOSb212bihCtxAQAAAAAAACDGWMQFAAAAAAAAgBhjERcAAAAAAAAAYoyeuKVg98G96qqrnFydOnVM/P777zu5119/Pb8Tq4T8vjqNGjXK6XXsXpAtW7Z0cmPGjDFx//79nZzdD0dyeyL/8ccfkbk+ffo4uRYtWph4wIABTu7DDz/MOHcUht/7zR9n65JLLnHGdp+4Tz75xMnNnz8/p/cA1jv77LMjc3379nXGfi8wVAz2scjv3e2z/879v38gnxYsWOCMJ0yYYOI99tij0NOpdOxzWcnt1+8/38O2atUqZ5zpc6JZs2bOeLPNNovcduTIkZE5VC69e/d2xieeeGLktt99952J77333rzNCZumZs2aztj+vu4fF55//nkT2/1ppcJ8B7a/r59xxhlO7oMPPjBxrVq1nNx1111nYnribrolS5bk/T38dRu757bdw12Svvzyy7zPpyxwJS4AAAAAAAAAxBiLuAAAAAAAAAAQY+XeTuH77793xv6t6OWpatWqzviaa64x8emnn+7kfvzxx7TbSdKaNWvyMLvK7aeffnLG33zzjYmbNGni5Nq3b2/iBx980MktX77cxPPmzXNyBxxwgIntlgiSNG3aNGdst9O46667nNz555+f9v0kt4WC37IBFdvOO++cMb906VIT33PPPXmeDcqKffuffxvVNttsY+JHHnnEyZ133nn5nZjHnovktugYOnRoQecCoPLyWyZ06tTJxFOnTi30dCq91atXm7isblneYYcdst72o48+KpP3RMXTtWtXZ3zllVdGbrts2TJnbB831q1bV7YTQ5kZMWKEM7aPDbfffruTC4LAxP6aS6Htv//+ztiem6+i3G6P/6lbt25kLtc2ieWNK3EBAAAAAAAAIMZYxAUAAAAAAACAGGMRFwAAAAAAAABirNx74r7zzjvO2O4tW7t2bSdn9/hbsGBBmbz/fvvt54x79Ohh4pYtWzq51q1bR77OmWeeaWL6PRWe3Xf2lVdecXIdOnQw8euvv+7kBg0aZGK/J67toIMOcsbXX399ZN7vozNjxgwT33jjjU5u9OjRke+Jiu2mm27KmH/ppZdMPGnSpHxPB2Xkiy++MHGvXr2c3GOPPWbiU0891cndf//9Js7X3/dDDz1k4m233dbJPffccyZeuXJlXt4f+dW2bduMYxQ3v3+k3ed6+PDhhZ5ORvazCW655RYnt+WWW5rYP06iYurSpUt5TwExdcQRR5jYfy5Jpr6jf/vb35zx119/XabzQmEMGzbMxMcee6yTa9eunYmfeOIJJzd+/HgT//Of/3RyM2fOzGkuPXv2dMYXXHCBiZs2berkMtUmisuff/5Z3lPICVfiAgAAAAAAAECMsYgL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\n",
      "text/plain": [
       "<Figure size 1800x288 with 20 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "dataiter = iter(test_loader)\n",
    "images, labels = dataiter.next()\n",
    "output = model(images)\n",
    "_, preds = torch.max(output, 1)\n",
    "images = images.numpy()\n",
    "\n",
    "fig = plt.figure(figsize=(25, 4))\n",
    "for idx in np.arange(20):\n",
    "  ax = fig.add_subplot(2, 20/2, idx+1, xticks=[], yticks=[])\n",
    "  ax.imshow(np.squeeze(images[idx]), cmap='gray')\n",
    "  ax.set_title('{} ({})'.format(str(preds[idx].item()), str(labels[idx].item())),\n",
    "               color = (\"green\" if preds[idx]==labels[idx] else \"red\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAV0AAADnCAYAAAC9roUQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAADKUlEQVR4nO3UMQEAIAzAMMC/5+GiHCQKenXPzAKgcV4HAPzEdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIGS6ACHTBQiZLkDIdAFCpgsQMl2AkOkChEwXIHQBcjcEy3+fc28AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAAJRCAYAAABlfOLeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAN9ElEQVR4nO3bPYud1QKG4bXNTiHYqESw0BisbMSPCIIKEZugpf6F2AQbIaUIlpYW/gMbKwuRQYighabIFEJCUBzBKCIok0KFoMJ7+qDnTG5Xzp7JXFf5snhY5T1rM6tlWQYAADfnjk1fAADgIBJRAACBiAIACEQUAEAgogAAgvXNHF6tVv6VDwA4bH5ZluXYjR+9RAEA/Hff/d1HEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAI1pu+APvTK6+8Mn3zzJkz0zd//PHHqXvXr1+fujfGGO+9997UvZ9++mnq3hhjfPPNN9M3AW53XqIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABKtlWfZ+eLXa+2EOtG+//Xb65kMPPTR98zD69ddfp29evnx5+iZUP/zww/TNt99+e/rmxYsXp2+yb20vy3Lyxo9eogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgGC96QuwP505c2b65qOPPjp988qVK1P3Hnnkkal7Y4zxxBNPTN07derU1L0xxnj66aen7n3//fdT98YY44EHHpi+eRD89ddfU/d+/vnnqXtjjHH//fdP35zt6tWr0zcvXrw4fZODxUsUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgGC96QuwP50/f/5AbM62tbW16Sv8T3fffff0zccee2zq3vb29tS9McZ46qmnpm8eBNevX5+69/XXX0/dG2OMK1euTN275557pu6NMcbOzs70TfASBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABKtlWfZ+eLXa+2EA9p2XX355+ub7778/de/SpUtT98YY4/nnn5++ubu7O32TfWt7WZaTN370EgUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgWG/6AgD8s/vuu2/q3rvvvjt1b4wx7rhj7t/jb7311tS9McbY3d2dvgleogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgGC96QsA8M/Onj07de/YsWNT98YY49q1a1P3vvrqq6l7cKt4iQIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQrJZl2fvh1WrvhwEOmWeeeWb65ieffDJ17+jRo1P3xhjj1KlTU/c+++yzqXswwfayLCdv/OglCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAECw3vQFAG4XL7744vTNo0ePTt07f/781L0xxvjiiy+mb8JB4CUKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAI1pu+AMCm3HnnnVP3Tp8+PXVvjDH++OOPqXtvvvnm1L0xxvjzzz+nb8JB4CUKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQLDe9AUANuXcuXNT9x5//PGpe2OMsbW1NXXv888/n7oHh5mXKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIFgty7L3w6vV3g8DTPTSSy9N3/zggw+m7v3+++9T98YY4/Tp01P3Lly4MHUPDontZVlO3vjRSxQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAYL3pCwC3n3vvvXf65jvvvDN988iRI1P3Pvroo6l7Y4xx4cKF6ZvAHF6iAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAYL3pCwCbd+TIkal7W1tbU/fGGOPEiRPTN3d2dqbuvfHGG1P3gP3NSxQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAYL3pCwCb9/DDD0/de/LJJ6fu3Sqvv/761L2dnZ2pe8D+5iUKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQLDe9AWAm3P8+PHpmx9//PH0zdnOnTs3ffPDDz+cvgkcHl6iAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAYL3pCwA359VXX52++eCDD07fnO3TTz+dvrksy/RN4PDwEgUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgWG/6AnC7e/bZZ6fuvfbaa1P3AGi8RAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAMF60xeA291zzz03de+uu+6auncr7OzsTN/87bffpm8C/BteogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAE601fANi8L7/8cureCy+8MHVvjDF2d3enbwL8G16iAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAYLUsy94Pr1Z7PwwAcHvYXpbl5I0fvUQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACNY3ef6XMcZ3t+IiAAD71PG/+7haluX/fREAgAPPz3kAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAwX8AnkLo6ri0bD0AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.axis('off')\n",
    "plt.figure(figsize=(8, 8))\n",
    "plt.imshow(np.squeeze(images[0]), cmap='gray')\n",
    "# fig.set_size_inches(0.28/3, 0.28/3) #dpi = 300, output = 700*700 pixels\n",
    "\n",
    "plt.gca().xaxis.set_major_locator(plt.NullLocator())\n",
    "plt.gca().yaxis.set_major_locator(plt.NullLocator())\n",
    "plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, hspace = 0, wspace = 0)\n",
    "plt.margins(0,0)\n",
    "\n",
    "plt.rcParams['savefig.dpi'] = 28 * 28\n",
    "# plt.show()\n",
    "\n",
    "plt.savefig(\"./temp.png\", bbox_inches='tight', pad_inches=0.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "# third-party library\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "from torch.autograd import Variable\n",
    "import torch.utils.data as Data\n",
    "import torchvision\n",
    "import matplotlib.pyplot as plt \n",
    "# torch.manual_seed(1)  # reproducible\n",
    "DOWNLOAD_MNIST = False\n",
    "  \n",
    "# Mnist digits dataset\n",
    "if not(os.path.exists('./mnist/')) or not os.listdir('./mnist/'):\n",
    "  # not mnist dir or mnist is empyt dir\n",
    "  DOWNLOAD_MNIST = True\n",
    "  \n",
    "train_data = torchvision.datasets.MNIST(\n",
    "  root='./data/MNIST/',\n",
    "  train=True,                   # this is training data\n",
    "  transform=torchvision.transforms.ToTensor(),  # Converts a PIL.Image or numpy.ndarray to\n",
    "                          # torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]\n",
    "  download=DOWNLOAD_MNIST,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from skimage import io\n",
    "import torchvision.datasets.mnist as mnist\n",
    "import numpy \n",
    "root = \"./data/MNIST/raw/\"\n",
    "train_set = (\n",
    "  mnist.read_image_file(os.path.join(root, 'train-images-idx3-ubyte')),\n",
    "  mnist.read_label_file(os.path.join(root, 'train-labels-idx1-ubyte'))\n",
    ")\n",
    "  \n",
    "test_set = (\n",
    "  mnist.read_image_file(os.path.join(root,'t10k-images-idx3-ubyte')),\n",
    "  mnist.read_label_file(os.path.join(root,'t10k-labels-idx1-ubyte'))\n",
    ")\n",
    "  \n",
    "print(\"train set:\", train_set[0].size())\n",
    "print(\"test set:\", test_set[0].size())\n",
    "  \n",
    "def convert_to_img(train=True):\n",
    "  if(train):\n",
    "    f = open(root + 'train.txt', 'w')\n",
    "    data_path = root + '/train/'\n",
    "    if(not os.path.exists(data_path)):\n",
    "      os.makedirs(data_path)\n",
    "    for i, (img, label) in enumerate(zip(train_set[0], train_set[1])):\n",
    "      img_path = data_path + str(i) + '.jpg'\n",
    "      io.imsave(img_path, img.numpy())\n",
    "      int_label = str(label).replace('tensor(', '')\n",
    "      int_label = int_label.replace(')', '')\n",
    "      f.write(img_path + ' ' + str(int_label) + '\\n')\n",
    "      if i > 30:\n",
    "        break\n",
    "    f.close()\n",
    "  \n",
    "convert_to_img(True)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!tar -cvf  imgs.tar.gz ./data/MNIST/raw/train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
